﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using NUnit.Framework;
using SellAndBuy.Application.Services;
using SellAndBuy.Domain.Entities;
using SellAndBuy.Application.Query.Finders;
using SellAndBuy.Domain.Repositories;
using SellAndBuy.Infrastructure.Core.Logging;
using SellAndBuy.Infrastructure.Core.Logging.NullLogger;
using SellAndBuy.Infrastructure.Data.Core;
using SellAndBuy.Infrastructure.Data.Core.Factories;
using SellAndBuy.Infrastructure.Data.Query.Finders;
using SellAndBuy.Infrastructure.Data.Repositories;
using SellAndBuy.Specs.Utilities;
using SellAndBuy.Web.Controllers;
using SellAndBuy.Web.ViewModels;
using TechTalk.SpecFlow;

namespace SellAndBuy.Specs.Steps
{
    [Binding]
    public class ListRecentAdsSteps
    {
        private ActionResult _actionResult;

        private NHibernateFactory _factory;
        private INhibernateUnitOfWork _unitOfWork;
        private ILogger _logger;

        private ICustomerRepository GetCustomerRepository()
        {
            return new CustomerRepository(_unitOfWork);
        }

        private ICustomerFinder GetCustomerFinder()
        {
            return new CustomerFinder(_unitOfWork);
        }

        private IAdRepository GetAdRepository()
        {
            return new AdRepository(_unitOfWork);
        }

        private IAdFinder GetAdFinder()
        {
            return new AdFinder(_unitOfWork);
        }

        private IItemRepository GetItemRepository()
        {
            return new ItemRepository(_unitOfWork);
        }

        private IItemFinder GetItemFinder()
        {
            return new ItemFinder(_unitOfWork);
        }

        private ICategoryRepository GetCategoryRepository()
        {
            return new CategoryRepository(_unitOfWork);
        }

        private ICategoryFinder GetCategoryFinder()
        {
            return new CategoryFinder(_unitOfWork);
        }

        private IAdQueryService GetAdQueryService()
        {
            return new AdQueryService(GetAdFinder(), GetItemFinder(), GetCategoryFinder());
        }

        [BeforeScenario]
        public void InitializeSchema()
        {
            _logger = new NullLogger();
            _factory = new NHibernateFactory();
            _unitOfWork = new LoggedUnitOfWork(new UnitOfWork(_factory), _logger);
            _factory.CreateSchema();
        }
        
        [Given(@"the follwing customers")]
        public void GivenTheFollwingCustomers(Table table)
        {
            var customers = new List<Customer>();
            foreach (var tableRow in table.Rows)
            {
                var customer = new Customer
                                   {
                                       FirstName = tableRow["First Name"],
                                       LastName = tableRow["Last Name"],
                                       Email = tableRow["Email"]
                                   };
                customers.Add(customer);
            }

            foreach (var customer in customers)
            {
                GetCustomerRepository().Add(customer);  
            }
            
            GetCustomerRepository().UnitOfWork.Commit();
        }

        [Given(@"the category ""(.*)""")]
        public void GivenTheCategory(string category)
        {
            var cat = new ItemCategory {Name = category};
            var repository = GetCategoryRepository();
            repository.Add(cat);
            repository.UnitOfWork.Commit();
        }

        [Given(@"the following conditions for the category ""(.*)""")]
        public void GivenTheFollowingConditionsForTheCategory(string categoryName,Table table)
        {
            var category = GetCategoryRepository().FindBy(c => c.Name == categoryName);
            foreach (var tableRow in table.Rows)
            {
                category.AddCondition(tableRow["Name"]);
            }

            GetCategoryRepository().Update(category);
            GetCategoryRepository().UnitOfWork.Commit();
        }

        [Given(@"the folowing items")]
        public void GivenTheFolowingItems(Table table)
        {
            foreach (var tableRow in table.Rows)
            {
                var item = new Item(GetCategoryRepository().FindBy(c => c.Name == tableRow["Category"]))
                               {
                                   Name = tableRow["Title"],
                                   Description = tableRow["Description"]
                               };
                GetItemRepository().Add(item);
            }
            GetItemRepository().UnitOfWork.Commit();
        }

        [Given(@"the following ads")]
        public void GivenTheFollowingAds(Table table)
        {
            var customers = GetCustomerFinder().FindAll();
            var Ads = new List<Ad>();
            foreach (var tableRow in table.Rows)
            {
                var customer = customers.First(c => c.Email == tableRow["Customer Email"]);
                var item = GetItemRepository().FindBy(i => i.Name == tableRow["Item"]);
                var Ad = new Ad(GetCustomerRepository().Find(customer.ID) , item)
                                      {
                                          Description = tableRow["Description"],
                                          Price = Decimal.Parse(tableRow["Price"]),
                                          Condition = item.Category.GetCondition(tableRow["Condition"])
                                      };
                Ads.Add(Ad);
            }

            foreach (var ad in Ads)
            {
                GetAdRepository().Add(ad);                
            }

            GetAdRepository().UnitOfWork.Commit();
        }

        [When(@"I enter home page")]
        public void WhenIEnterHomePage()
        {
            var controller = new HomeController();

            _actionResult = controller.Index(null, null);
        }

        [Then(@"the home page shows ads")]
        public void ThenTheHomePageShowsAds(Table table)
        {
            var adsViewModel = _actionResult.Model<AdListViewModel>();

            foreach (var row in table.Rows)
            {
                CustomAssert.Any(adsViewModel.PageItems,
                                 a =>
                                 a.Title == row["Title"] && a.Description == row["Description"] &&
                                 a.Price == Decimal.Parse(row["Price"]) &&
                                 a.Owner == row["Owner"]);
            }

            Assert.AreEqual(table.Rows.Count(), adsViewModel.PageItems.Count(), "The list count is not matching");
        }
    }
}